/******************************************************************************
 *
 * Copyright(c) 2019 Realtek Corporation.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of version 2 of the GNU General Public License as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details.
 *
 *****************************************************************************/
#include "../halrf_precomp.h"

#ifdef RF_8851B_SUPPORT

void _halrf_psd_backup_bb_registers_8851b(
	struct rf_info *rf,
	enum phl_phy_idx phy,
	u32 *reg,
	u32 *reg_backup,
	u32 reg_num)
{
	u32 i;

	for (i = 0; i < reg_num; i++) {
		reg_backup[i] = halrf_rreg(rf, reg[i], MASKDWORD);

		RF_DBG(rf, DBG_RF_PSD, "[PSD] Backup BB 0x%08x = 0x%08x\n",
		       reg[i], reg_backup[i]);
	}
}

void _halrf_psd_reload_bb_registers_8851b(
	struct rf_info *rf,
	enum phl_phy_idx phy,
	u32 *reg,
	u32 *reg_backup,
	u32 reg_num)

{
	u32 i;

	for (i = 0; i < reg_num; i++) {
		halrf_wreg(rf, reg[i], MASKDWORD, reg_backup[i]);

		RF_DBG(rf, DBG_RF_PSD, "[PSD] Reload BB 0x%08x = 0x%08x\n",
		       reg[i], reg_backup[i]);
	}
}

void _halrf_psd_set_dac_off_adc_8851b(struct rf_info *rf, enum phl_phy_idx phy)

{
	u8 bw = rf->hal_com->band[phy].cur_chandef.bw;

	RF_DBG(rf, DBG_RF_PSD, "======> %s   phy=%d   bw=%d\n",
		__func__, phy, bw);

	if (bw == CHANNEL_WIDTH_20) {
		/*05_BW20_DAC_off_ADC080_and_RxCFIR_path0_KS_51B_*/
		halrf_wreg(rf, 0x20fc, 0xffff0000, 0x0101);
		halrf_wreg(rf, 0x5670, 0x00002000, 0x1);
		halrf_wreg(rf, 0x12a0, 0x00080000, 0x1);
		halrf_wreg(rf, 0x12a0, 0x00070000, 0x2);
		halrf_wreg(rf, 0x5670, 0x60000000, 0x0);
		halrf_wreg(rf, 0xc0d4, 0x00000780, 0x8);
		halrf_wreg(rf, 0xc0d4, 0x00007800, 0x2);
		halrf_wreg(rf, 0xc0d4, 0x0c000000, 0x2);
		halrf_wreg(rf, 0xc0d8, 0x000001e0, 0x5);
		halrf_wreg(rf, 0xc0c4, 0x003e0000, 0xf);
		halrf_wreg(rf, 0xc0ec, 0x00006000, 0x2);
		halrf_wrf(rf, RF_PATH_A, 0x8f, 0x01000, 0x1);
		halrf_wreg(rf, 0x12b8, 0x40000000, 0x1);
		halrf_wreg(rf, 0x030c, 0xff000000, 0x0f);
		halrf_wreg(rf, 0x030c, 0xff000000, 0x03);
		halrf_wreg(rf, 0x032c, 0xffff0000, 0x0001);
		halrf_wreg(rf, 0x032c, 0xffff0000, 0x0041);
		halrf_wreg(rf, 0x20fc, 0xffff0000, 0x1101);
		halrf_wreg(rf, 0x8120, MASKDWORD, 0x40000a08);
		halrf_wreg(rf, 0x8128, 0x000000ff, 0x84);
	} else if (bw == CHANNEL_WIDTH_40) {
		/*05_BW40_DAC_off_ADC080_and_RxCFIR_path0_KS_51B*/
		halrf_wreg(rf, 0x20fc, 0xffff0000, 0x0101);
		halrf_wreg(rf, 0x5670, 0x00002000, 0x1);
		halrf_wreg(rf, 0x12a0, 0x00080000, 0x1);
		halrf_wreg(rf, 0x12a0, 0x00070000, 0x2);
		halrf_wreg(rf, 0x5670, 0x60000000, 0x0);
		halrf_wreg(rf, 0xc0d4, 0x00000780, 0x8);
		halrf_wreg(rf, 0xc0d4, 0x00007800, 0x2);
		halrf_wreg(rf, 0xc0d4, 0x0c000000, 0x2);
		halrf_wreg(rf, 0xc0d8, 0x000001e0, 0x5);
		halrf_wreg(rf, 0xc0c4, 0x003e0000, 0xf);
		halrf_wreg(rf, 0xc0ec, 0x00006000, 0x2);
		halrf_wrf(rf, RF_PATH_A, 0x8f, 0x01000, 0x1);
		halrf_wreg(rf, 0x12b8, 0x40000000, 0x1);
		halrf_wreg(rf, 0x030c, 0xff000000, 0x0f);
		halrf_wreg(rf, 0x030c, 0xff000000, 0x03);
		halrf_wreg(rf, 0x032c, 0xffff0000, 0x0001);
		halrf_wreg(rf, 0x032c, 0xffff0000, 0x0041);
		halrf_wreg(rf, 0x20fc, 0xffff0000, 0x1101);
		halrf_wreg(rf, 0x8120, MASKDWORD, 0x40000a08);
		halrf_wreg(rf, 0x8128, 0x000000ff, 0x85);		
	} else if (bw == CHANNEL_WIDTH_80) {
		/*05_BW80_DAC_off_ADC160_and_RxCFIR_path0_KS_51B*/
		halrf_wreg(rf, 0x20fc, 0xffff0000, 0x0101);
		halrf_wreg(rf, 0x5670, 0x00002000, 0x1);
		halrf_wreg(rf, 0x12a0, 0x00080000, 0x1);
		halrf_wreg(rf, 0x12a0, 0x00070000, 0x2);
		halrf_wreg(rf, 0x5670, 0x60000000, 0x1);
		halrf_wreg(rf, 0xc0d4, 0x00000780, 0x8);
		halrf_wreg(rf, 0xc0d4, 0x00007800, 0x2);
		halrf_wreg(rf, 0xc0d4, 0x0c000000, 0x2);
		halrf_wreg(rf, 0xc0d8, 0x000001e0, 0x5);
		halrf_wreg(rf, 0xc0c4, 0x003e0000, 0xf);
		halrf_wreg(rf, 0xc0ec, 0x00006000, 0x0);
		halrf_wrf(rf, RF_PATH_A, 0x8f, 0x01000, 0x1);
		halrf_wreg(rf, 0x12b8, 0x40000000, 0x1);
		halrf_wreg(rf, 0x030c, 0xff000000, 0x0f);
		halrf_wreg(rf, 0x030c, 0xff000000, 0x03);
		halrf_wreg(rf, 0x032c, 0xffff0000, 0x0001);
		halrf_wreg(rf, 0x032c, 0xffff0000, 0x0041);
		halrf_wreg(rf, 0x20fc, 0xffff0000, 0x1101);
		halrf_wreg(rf, 0x8120, MASKDWORD, 0x41000a08);
		halrf_wreg(rf, 0x8128, 0x000000ff, 0x86);
	}
}

void halrf_psd_init_8851b(struct rf_info *rf, enum phl_phy_idx phy,
			u8 path, u8 iq_path, u32 avg, u32 fft)
{
	struct halrf_psd_data *psd_info = &rf->psd;

	u32 tmp;
	u32 bb_reg[PSD_BACKUP_NUM_8851B] = {
			0x20fc, 0x5670, 0x12a0, 0xc0d4, 0xc0d8,
			0xc0c4, 0xc0ec, 0xc0e8, 0x12b8, 0x030c,
			0x032c, 0x8080, 0x8008, 0x8088, 0x80d0,
			0x8074, 0x81dc, 0x8120, 0x8128, 0x8154,
			0x8140, 0x8144, 0x8000, 0x8034, 0x8018,
			0x81cc, 0x801c, 0x802c, 0x80d4, 0x80fc};

	RF_DBG(rf, DBG_RF_PSD, "======> %s   phy=%d\n", __func__, phy);

	psd_info->psd_progress = 1;

	_halrf_psd_backup_bb_registers_8851b(rf, phy, bb_reg,
			psd_info->psd_reg_backup, PSD_BACKUP_NUM_8851B);

	psd_info->path = path;
	psd_info->iq_path = iq_path;
	psd_info->avg = avg;
	psd_info->fft = fft;

	/*01_BB_AFE_forDPK_S0_20220829_51BPSD*/
	halrf_wrf(rf, RF_PATH_A, 0x10005, 0x00001, 0x0);
	halrf_wreg(rf, 0x20fc, 0x00010000, 0x1);
	halrf_wreg(rf, 0x20fc, 0x00100000, 0x0);
	halrf_wreg(rf, 0x20fc, 0x01000000, 0x1);
	halrf_wreg(rf, 0x20fc, 0x10000000, 0x0);
	halrf_wreg(rf, 0x5670, MASKDWORD, 0xf801fffd);
	halrf_wreg(rf, 0x5670, 0x00004000, 0x1);
	halrf_wreg(rf, 0x12a0, 0x00008000, 0x1);
	halrf_wreg(rf, 0x5670, 0x80000000, 0x1);
	halrf_wreg(rf, 0x12a0, 0x00007000, 0x7);
	halrf_wreg(rf, 0x5670, 0x00002000, 0x1);
	halrf_wreg(rf, 0x12a0, 0x00080000, 0x1);
	halrf_wreg(rf, 0x12a0, 0x00070000, 0x3);
	halrf_wreg(rf, 0x5670, 0x60000000, 0x2);
	halrf_wreg(rf, 0xc0d4, 0x00000780, 0x9);
	halrf_wreg(rf, 0xc0d4, 0x00007800, 0x1);
	halrf_wreg(rf, 0xc0d4, 0x0c000000, 0x1);
	halrf_wreg(rf, 0xc0d8, 0x000001e0, 0x3);
	halrf_wreg(rf, 0xc0c4, 0x003e0000, 0xf);
	halrf_wreg(rf, 0xc0ec, 0x00006000, 0x0);
	halrf_wreg(rf, 0xc0e8, 0x00000040, 0x1);
	halrf_wreg(rf, 0x12b8, 0x40000000, 0x1);
	halrf_wreg(rf, 0x030c, 0xff000000, 0x1f);
	halrf_wreg(rf, 0x030c, 0xff000000, 0x13);
	halrf_wreg(rf, 0x032c, 0xffff0000, 0x0001);
	halrf_wreg(rf, 0x032c, 0xffff0000, 0x0041);
	halrf_wreg(rf, 0x20fc, 0x00100000, 0x1);
	halrf_wreg(rf, 0x20fc, 0x10000000, 0x1);	
	
	/*02_IQKPSD_Preset_path0*/
	halrf_wreg(rf, 0x8080, MASKDWORD, 0x00000006);
	halrf_wrf(rf, RF_PATH_A, 0x5, 0x00001, 0x0);
	halrf_wreg(rf, 0x8008, MASKDWORD, 0x00000080);
	halrf_wreg(rf, 0x8088, MASKDWORD, 0x81ff010a);
	halrf_wreg(rf, 0x80d0, MASKDWORD, 0x00200000);
	halrf_wreg(rf, 0x8074, MASKDWORD, 0x80000000);
	halrf_wreg(rf, 0x81dc, MASKDWORD, 0x00000000);

	_halrf_psd_set_dac_off_adc_8851b(rf, phy);
	
	/*06a_S0_IQKPSD_Apply_RxCFIR*/
	halrf_wreg(rf, 0x8154, 0x00000100, 0x0);
	halrf_wreg(rf, 0x8140, 0x00000100, 0x1);
	tmp = halrf_rrf(rf, RF_PATH_A, 0x00, 0x03800);
	halrf_wreg(rf, 0x8144, 0x00070000, tmp);
	tmp = halrf_rrf(rf, RF_PATH_A, 0x00, 0x003e0);
	halrf_wreg(rf, 0x8144, 0x1f000000, tmp);
	halrf_wreg(rf, 0x81dc, MASKDWORD, 0x00000001);
	halrf_wreg(rf, 0x81dc, MASKDWORD, 0x00000000);

	/*06b_S0_IQKPSD*/
	halrf_wreg(rf, 0x8000, MASKDWORD, 0x00000008);
	halrf_wreg(rf, 0x8034, 0x00000030, 0x3);
	/*halrf_wreg(rf, 0x8018, MASKDWORD, 0x40010101);*/
	halrf_wreg(rf, 0x8018, 0xfffffffe, 0x20008080);
	halrf_wreg(rf, 0x8018, 0x70000000, 0x4);
	halrf_wreg(rf, 0x80d0, MASKDWORD, 0x00300000);
	halrf_wreg(rf, 0x81cc, 0x0000003f, 0x3f);

	if (fft == 160)
		halrf_wreg(rf, 0x801c, 0x00003000, 0x0);
	else if (fft == 320)
		halrf_wreg(rf, 0x801c, 0x00003000, 0x1);
	else if (fft == 640)
		halrf_wreg(rf, 0x801c, 0x00003000, 0x2);
	else /*1280*/
		halrf_wreg(rf, 0x801c, 0x00003000, 0x3);

	if (avg == 1)
		halrf_wreg(rf, 0x801c, 0x000e0000, 0x0);
	else if (avg == 2)
		halrf_wreg(rf, 0x801c, 0x000e0000, 0x1);
	else if (avg == 4)
		halrf_wreg(rf, 0x801c, 0x000e0000, 0x2);
	else if (avg == 8)
		halrf_wreg(rf, 0x801c, 0x000e0000, 0x3);
	else if (avg == 16)
		halrf_wreg(rf, 0x801c, 0x000e0000, 0x4);
	else if (avg == 64)
		halrf_wreg(rf, 0x801c, 0x000e0000, 0x6);
	else if (avg == 128)
		halrf_wreg(rf, 0x801c, 0x000e0000, 0x7);
	else	/*32*/
		halrf_wreg(rf, 0x801c, 0x000e0000, 0x5);

	halrf_wreg(rf, 0x8018, 0x00000006, iq_path);
}

void halrf_psd_restore_8851b(struct rf_info *rf, enum phl_phy_idx phy)
{
	struct halrf_psd_data *psd_info = &rf->psd;
	u32 bb_reg[PSD_BACKUP_NUM_8851B] = {
			0x20fc, 0x5670, 0x12a0, 0xc0d4, 0xc0d8,
			0xc0c4, 0xc0ec, 0xc0e8, 0x12b8, 0x030c,
			0x032c, 0x8080, 0x8008, 0x8088, 0x80d0,
			0x8074, 0x81dc, 0x8120, 0x8128, 0x8154,
			0x8140, 0x8144, 0x8000, 0x8034, 0x8018,
			0x81cc, 0x801c, 0x802c, 0x80d4, 0x80fc};

	RF_DBG(rf, DBG_RF_PSD, "======> %s   phy=%d\n", __func__, phy);

	_halrf_psd_reload_bb_registers_8851b(rf, phy, bb_reg,
			psd_info->psd_reg_backup, PSD_BACKUP_NUM_8851B);

	halrf_wrf(rf, RF_PATH_A, 0x5, 0x00001, 0x1);

	halrf_wrf(rf, RF_PATH_A, 0x10005, 0x00001, 0x1);

	psd_info->psd_progress = 0;

#if 0
	/*98_S0_IQK_Reg_Restore_51B_20220823*/
	halrf_wreg(rf, 0x8000, MASKDWORD, 0x00001219);
	halrf_delay_us(rf, 100);
	halrf_wreg(rf, 0x8010, 0x000000ff, 0x00);
	halrf_wreg(rf, 0x8008, MASKDWORD, 0x00000000);
	halrf_wreg(rf, 0x8088, MASKDWORD, 0x80000000);
	halrf_wrf(rf, RF_PATH_A, 0xef, 0x00004, 0x0);
	halrf_wrf(rf, RF_PATH_A, 0x0, 0xf0000, 0x3);
	halrf_wrf(rf, RF_PATH_A, 0x5, 0x00001, 0x1);

	/*99_BB_AFE_Non_DBCC_PHY0_path01_restore*/
	//halrf_wreg(rf, 0xc0ec, 0x00006000, varfromtmp);
	halrf_wreg(rf, 0x12b8, 0x40000000, 0x0);
	halrf_wreg(rf, 0x20fc, 0x00010000, 0x1);
	halrf_wreg(rf, 0x20fc, 0x00100000, 0x0);
	halrf_wreg(rf, 0x20fc, 0x01000000, 0x1);
	halrf_wreg(rf, 0x20fc, 0x10000000, 0x0);
	halrf_wreg(rf, 0x5670, MASKDWORD, 0x00000000);
	halrf_wreg(rf, 0x12a0, 0x000ff000, 0x00);
	halrf_wreg(rf, 0x20fc, 0x00010000, 0x0);
	halrf_wreg(rf, 0x20fc, 0x01000000, 0x0);
	halrf_wreg(rf, 0xc0e8, 0x00000040, 0x0);
	halrf_wrf(rf, RF_PATH_A, 0x10005, 0x00001, 0x1);
#endif
}

u32 halrf_psd_get_point_data_8851b(struct rf_info *rf,
			enum phl_phy_idx phy, s32 point)
{
	u32 val_tmp, val, data;

	halrf_wreg(rf, 0x802c, 0x0fff0000, (point & 0xfff));
	halrf_wreg(rf, 0x8034, 0x00000001, 0x1);
	halrf_wreg(rf, 0x8034, 0x00000001, 0x0);
	halrf_delay_us(rf, 500);

	halrf_wreg(rf, 0x80d4, 0xffffffff, 0x002d0000);
	val_tmp = halrf_rreg(rf, 0x80fc, 0x007f0000);
	halrf_wreg(rf, 0x80d4, 0xffffffff, 0x002e0000);
	val = halrf_rreg(rf, 0x80fc, 0xffffffff);

	data = (val_tmp << 25) | (val >> 7);

	return data;
}

void halrf_psd_query_8851b(struct rf_info *rf, enum phl_phy_idx phy,
			u32 point, u32 start_point, u32 stop_point, u32 *outbuf)
{
	struct halrf_psd_data *psd_info = &rf->psd;
	u32 i = 0, j = 0;
	s32 point_temp = 0;

	RF_DBG(rf, DBG_RF_PSD, "======> %s phy=%d point=%d start_point=%d stop_point=%d\n",
		__func__, phy, point, start_point, stop_point);

#ifdef PHL_PLATFORM_AP
	if (psd_info->psd_result_running == 2) {
		for (i = 0; i < PSD_RF_DATA_NUM; i++)
			outbuf[i] = psd_info->psd_data[i];

		RF_DBG(rf, DBG_RF_PSD, "======> %s PSD End !!!\n", __func__);

		psd_info->psd_result_running = 0;
		return;
	}
#else
	if (psd_info->psd_result_running == 1) {
		RF_DBG(rf, DBG_RF_PSD, "======> %s PSD Running Return !!!\n", __func__);
		return;
	}
	psd_info->psd_result_running = 1;
#endif

	for (i = 0; i < PSD_RF_DATA_NUM; i++)
		psd_info->psd_data[i] = 0;

	i = start_point;
	while (i < stop_point) {
		if (i >= point)
			point_temp = i - point;
		else
		{
			point_temp = i - point;
			point_temp = point_temp & 0xfff;
		}

		psd_info->psd_data[j] = halrf_psd_get_point_data_8851b(rf, phy, point_temp);

		i++;
		j++;
	}

	RF_DBG(rf, DBG_RF_PSD, "PSD Point = Start:%d   End:%d\n",
		start_point - point, point_temp);

	for (i = 0; i < PSD_RF_DATA_NUM; i = i + 10) {
		RF_DBG(rf, DBG_RF_PSD,
			"%d   %d   %d   %d   %d   %d   %d   %d   %d   %d\n",
			psd_info->psd_data[i],
			psd_info->psd_data[i + 1],
			psd_info->psd_data[i + 2],
			psd_info->psd_data[i + 3],
			psd_info->psd_data[i + 4],
			psd_info->psd_data[i + 5],
			psd_info->psd_data[i + 6],
			psd_info->psd_data[i + 7],
			psd_info->psd_data[i + 8],
			psd_info->psd_data[i + 9]);
	}

	for (i = 0; i < PSD_RF_DATA_NUM; i++)
		outbuf[i] = psd_info->psd_data[i];

	RF_DBG(rf, DBG_RF_PSD, "======> %s PSD End !!!\n", __func__);

#ifdef PHL_PLATFORM_AP
	psd_info->psd_result_running = 2;
#else
	psd_info->psd_result_running = 0;
#endif
}

#endif	/*RF_8851B_SUPPORT*/
